// Copyright 2019, Chen Shuaihao.
//
//Author: Chen Shuaihao
//
//
        //    typedef union epoll_data {
        //        void    *ptr;
        //        int      fd;
        //        uint32_t u32;
        //        uint64_t u64;
        //    } epoll_data_t;

        //    struct epoll_event {
        //        uint32_t     events;    /* Epoll events */
        //        epoll_data_t data;      /* User data variable */
        //    };

#include "Poller.h"
#include <iostream>
#include <stdio.h> //perror
#include <stdlib.h> //exit
#include <unistd.h> //close
#include <errno.h>

#define EVENTNUM 4096 //最大触发事件数量
#define TIMEOUT  3000 //epoll_wait 超时时间设置

Poller::Poller(/* args */)
    : pollfd_(-1),
    eventlist_(EVENTNUM),
    mutex_()
{
    pollfd_ = epoll_create(256);
    if(pollfd_ == -1)
    {
        perror("epoll_create1");
        exit(1);
    }
    std::cout << "epoll_create" << pollfd_ << std::endl;
}

Poller::~Poller()
{
    close(pollfd_);
}

//等待I/O事件
void Poller::poll(EventList& eList)
{
    int timeout  = -1;
    int nfds = epoll_wait(pollfd_, &*eventlist_.begin(), (int)eventlist_.capacity(), timeout);
    
    //std::cout << "epoll_wait() count:" << nfds << std::endl;

    if(nfds == -1)
    {
        perror("Poller:epoll_wait error \n");
        return;
    }

    for(int i = 0; i < nfds; ++i)
    {
        eList.push_back(eventlist_[i]);
    }

    if(nfds == (int)eventlist_.capacity())
    {
        std::cout << "resize:" << nfds << std::endl;
        eventlist_.resize(nfds * 2);
    }
    //eventlist_.clear();
}

//添加事件
void Poller::AddEvent(sClient* p_Conn, int  nFd, uint32_t  eventType)
{
    int  fd = nFd;
    struct epoll_event ev;
    ev.events = eventType;

    //data是联合体
    //ev.data.fd = fd;
    ev.data.ptr = p_Conn; 
    if (p_Conn)
    {
        p_Conn->events = eventType;
    }

    if(epoll_ctl(pollfd_, EPOLL_CTL_ADD, fd, &ev) == -1)
    {
        printf("EPOLL_CTL_ADD:%p, %d\n ", p_Conn,nFd);

        if (errno == EBADF) 
        {
            perror("EPOLL_CTL_ADD  EBADF\n ");
        }
        if (errno == EEXIST)
        {
            perror("EPOLL_CTL_ADD  EEXIST\n ");
        }
        if (errno == EINVAL)
        {
            perror("EPOLL_CTL_ADD  EINVAL\n ");
        }
        if (errno == ENOMEM)
        {
            perror("EPOLL_CTL_ADD  ENOMEM\n ");
        }
        if (errno == ENOSPC)
        {
            perror("EPOLL_CTL_ADD  ENOSPC\n ");
        }
        if (errno == EPERM)
        {
            perror("EPOLL_CTL_ADD  EPERM\n ");
        }
        
        //exit(1);
    }

}

//删除事件
void Poller::RemoveEvent(sClient* p_Conn, int  nFd, uint32_t  eventType)
{
   // int fd = p_Conn->GetFd();
    int  fd = nFd;
    struct epoll_event ev;
    ev.events = eventType;
    ///ev.data.fd = fd
    ev.data.ptr = p_Conn;
   
    if(epoll_ctl(pollfd_, EPOLL_CTL_DEL, fd, &ev) == -1)
    {
        perror("epoll del error EPOLL_CTL_DEL");
       // exit(1);
    }
}

//更新事件
void Poller::UpdateEvent(sClient* p_Conn, int  nFd, uint32_t  eventType, int    nAdd)
{
    int fd = nFd;

    struct epoll_event ev;

    ev.events = eventType;
    
    //ev.data.fd = fd;
    ev.data.ptr = p_Conn;

    ev.events = p_Conn->events;                         //先把标记恢复回来

    if (nAdd == 0)
    {        
        ev.events |= eventType;                             //增加某个标记            
    }
    else if (nAdd == 1)
    {   
        ev.events &= ~eventType;                        //去掉某个标记
    }
    else
    {     
        ev.events = eventType;                              //完全覆盖            
    }

    p_Conn->events = ev.events;                         //记录该标记

    if(epoll_ctl(pollfd_, EPOLL_CTL_MOD, fd, &ev) == -1)
    {
        perror("epoll update error EPOLL_CTL_MOD");
        exit(1);
    }
}

